/**
 * 
 */
package registnet.courseDemand;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import registnet.dao.StudentView;

/**
 * The student cluster object. A student cluster holds students with same
 * recommended courses.
 * 
 * @author Dexter Ryan Carrasco
 */
public class StudentCluster {

	/** The list of students in the cluster */
	private List<StudentView> students;

	/** The list of common major courses */
	private List<String> commonMajorCourses;

	/** The schedule of the cluster as a whole */
	private final Schedule schedule;

	/** The string list of unscheduled courses */
	private Set<String> unscheduled;

	/** Default constructor of StudentCluster */
	public StudentCluster() {
		this.students = new ArrayList<StudentView>();
		this.commonMajorCourses = new ArrayList<String>();
		this.schedule = new Schedule();
		this.unscheduled = new HashSet<String>();
	}

	/**
	 * Adds a course to the common major courses
	 * 
	 * @param course
	 */
	public void addCommonMajorCourse(final String course) {
		this.commonMajorCourses.add(course);
	}

	/**
	 * Adds a schedule to the cluster (all the students in the cluster)
	 * 
	 * @param daysInt
	 * @param timeInt
	 * @param value
	 * @return true if schedule is added, false otherwise
	 */
	public boolean addSchedule(final List<Integer> daysInt,
			final int[] timeInt, final String value) {
		return this.getSchedule().addSchedule(daysInt, timeInt, value);
	}

	/**
	 * Adds a student in the student cluster
	 * 
	 * @param student
	 */
	public void addStudent(final StudentView student) {
		this.students.add(student);
	}

	/**
	 * Adds an unscheduled course
	 * 
	 * @param unscheduled
	 */
	public void addUnscheduledCourse(final String unscheduled) {
		this.unscheduled.add(unscheduled);
	}

	/**
	 * Adds a list of unscheduled courses
	 * 
	 * @param unscheduled
	 */
	public void addUnscheduledCourses(final List<String> unscheduled) {
		this.unscheduled.addAll(unscheduled);
	}

	/**
	 * Copies the cluster schedule to all the students in the cluster
	 */
	public void copyScheduleToStudents() {
		for (final Iterator<StudentView> studIter = this.students.iterator(); studIter
				.hasNext();) {
			final StudentView student = studIter.next();
			student.setStudentSchedule(this.getSchedule());
			student.setUnscheduledCourses(this.unscheduled);
		}
	}

	/**
	 * Divides the cluster into the specified number of smaller clusters
	 * 
	 * @param divisor
	 * @return list of smaller clusters
	 */
	public List<StudentCluster> divideInto(final int divisor) {
		final List<StudentCluster> dividedClusters = new ArrayList<StudentCluster>();

		final int clusterSize = this.size();
		StudentCluster smallCluster = new StudentCluster();

		if (divisor == 0) {
			return null;
		}

		for (int i = 0; i < clusterSize; i++) {
			if (i % divisor == 0) {
				if (smallCluster.size() == divisor) {
					dividedClusters.add(smallCluster);
				}
				smallCluster = new StudentCluster();
				smallCluster.setCommonMajorCourses(this.commonMajorCourses);
				smallCluster.setSchedule(this.schedule);
				smallCluster.setUnscheduled(this.unscheduled);
			}
			smallCluster.addStudent(this.students.get(i));
		}

		if (smallCluster.size() > 0) {
			dividedClusters.add(smallCluster);
		}

		if (dividedClusters.size() < 1) {
			return null;
		} else {
			return dividedClusters;
		}
	}

	/**
	 * Gets the list of common major courses
	 * 
	 * @return the commonCourses
	 */
	public List<String> getCommonMajorCourses() {
		return this.commonMajorCourses;
	}

	/**
	 * Gets the schedule of the cluster
	 * 
	 * @return the schedule
	 */
	public Schedule getSchedule() {
		return this.schedule;
	}

	/**
	 * Gets the list of students in the cluster
	 * 
	 * @return the students
	 */
	public List<StudentView> getStudents() {
		return this.students;
	}

	/**
	 * Gets the list of unscheduled courses
	 * 
	 * @return the unscheduled
	 */
	public Set<String> getUnscheduled() {
		return this.unscheduled;
	}

	/**
	 * Checks whether the specified student has the same major courses as the
	 * cluster
	 * 
	 * @param student
	 * @return true if student has same major courses,false otherwise
	 */
	public boolean hasSameMajorCourses(final StudentView student) {
		return student.hasSameMajorCourses(this.commonMajorCourses);
	}

	/**
	 * Checks whether the cluster (all the students in the cluster) is vacant in
	 * the specified days and time
	 * 
	 * @param daysInt
	 * @param timeInt
	 * @return true if vacant, false otherwise
	 */
	public boolean isVacant(final List<Integer> daysInt, final int[] timeInt) {
		return this.getSchedule().isVacant(daysInt, timeInt);
	}

	/**
	 * Removes an unscheduled course
	 * 
	 * @param course
	 */
	public void removeUnscheduled(final String course) {
		this.unscheduled.remove(course);
	}

	/**
	 * Sets the list of common major courses
	 * 
	 * @param commonMajorCourses
	 *            the commonCourses to set
	 */
	public void setCommonMajorCourses(final List<String> commonMajorCourses) {
		this.commonMajorCourses = new ArrayList<String>();
		this.commonMajorCourses.addAll(commonMajorCourses);
	}

	/**
	 * Sets the schedule of the cluster
	 * 
	 * @param schedule
	 *            the schedule to set
	 */
	public void setSchedule(final Schedule schedule) {
		this.schedule.copy(schedule);
	}

	/**
	 * Sets the list of students in the cluster
	 * 
	 * @param students
	 *            the students to set
	 */
	public void setStudents(final List<StudentView> students) {
		this.students = new ArrayList<StudentView>();
		this.students.addAll(students);
	}

	/**
	 * Sets the list of unscheduled courses
	 * 
	 * @param unscheduled
	 *            the unscheduled to set
	 */
	public void setUnscheduled(final Set<String> unscheduled) {
		this.unscheduled = new HashSet<String>();
		this.unscheduled.addAll(unscheduled);
	}

	/**
	 * Returns the number of students in the cluster
	 * 
	 * @return size of the cluster
	 */
	public int size() {
		return this.students.size();
	}

	/**
	 * Returns the student numbers of the students in the cluster
	 * 
	 * @return string of student number
	 */
	public String toStringStudents() {
		final StringBuffer sb = new StringBuffer();

		sb.append("Students : ");
		for (final Iterator<StudentView> it = this.getStudents().iterator(); it
				.hasNext();) {
			final StudentView student = it.next();
			sb.append(student.getStudentNumber());
			sb.append(":");
		}

		return sb.toString();
	}

	/**
	 * Returns the string of all students in the cluster and all the common
	 * courses of the cluster
	 * 
	 * @return string of students and courses
	 */
	public String toStringStudentsAndCourses() {
		final StringBuffer sb = new StringBuffer();

		// sb.append(this.size());
		// sb.append(" Students\n");
		for (final Iterator<StudentView> it = this.getStudents().iterator(); it
				.hasNext();) {
			sb.append(it.next().getStudentNumber());
			sb.append(":");
		}

		sb.append("--> Common Courses > ");
		for (final Iterator<String> it = this.getCommonMajorCourses()
				.iterator(); it.hasNext();) {
			sb.append(it.next());
			sb.append(":");
		}

		return sb.toString();
	}

	/**
	 * Returns the string of common courses of the cluster
	 * 
	 * @return string of common courses
	 */
	public String toStringSubjects() {
		final StringBuffer sb = new StringBuffer();

		sb.append(this.size());
		// sb.append(" Students\n");
		/*
		 * for (Iterator<Student> it = this.getStudents().iterator();
		 * it.hasNext();) { sb.append(it.next().getStudentNumber());
		 * sb.append(":"); }
		 */

		// sb.append("--> Common Courses > ");
		sb.append("--> ");
		for (final Iterator<String> it = this.getCommonMajorCourses()
				.iterator(); it.hasNext();) {
			sb.append(it.next());
			sb.append(":");
		}

		return sb.toString();
	}

	/**
	 * Returns the string of unscheduled courses
	 * 
	 * @return string of unscheduled courses
	 */
	public String toStringUnscheduled() {
		final StringBuffer sb = new StringBuffer();
		sb.append("Unscheduled : ");
		for (final Iterator<String> subjIter = this.unscheduled.iterator(); subjIter
				.hasNext();) {
			sb.append(subjIter.next());
			sb.append(":");
		}

		return sb.toString();
	}
}
